package com.example.Windturbine.Controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.Windturbine.Controller.ViewObject.Excel.PartExcel;
import com.example.Windturbine.Dao.ProductDOMapper;
import com.example.Windturbine.Dao.ProductInfoDOMapper;
import com.example.Windturbine.Dao.ProductUseDOMapper;
import com.example.Windturbine.DataObject.ProductInfoDO;
import com.example.Windturbine.DataObject.ProductUseDO;
import com.example.Windturbine.Error.BusinessException;
import com.example.Windturbine.Error.EmBusinessError;
import com.example.Windturbine.Listener.ExcelListener;
import com.example.Windturbine.Response.CommonResult;
import com.example.Windturbine.Service.CacheService;
import com.example.Windturbine.Service.Model.ProductModel;
import com.example.Windturbine.Service.ProductCalService;
import com.example.Windturbine.Service.ProductService;
import com.example.Windturbine.SimilarLearning.BP;
import com.example.Windturbine.Utils.FileUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.math.BigDecimal;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
 * @Author 丁永新
 * @Date 2021/12/16
 */
@Slf4j
@Controller("product")
@RequestMapping("/product")
@CrossOrigin(allowCredentials = "true", allowedHeaders = "*")
public class ProductController {
    @Autowired
    ProductService productService;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    CacheService cacheService;

    @Autowired
    ProductCalService productCalService;


    @Resource
    ProductUseDOMapper productUseDOMapper;


    @Resource
    ProductInfoDOMapper productInfoDOMapper;

    @Resource
    ProductDOMapper productDOMapper;

    @Autowired
    ExecutorService executorService;

    @Resource
    BP bp;

    static ConcurrentHashMap<String, MultipartFile> cache;

    /**
     * 获取所有用户的产品信息
     *
     * @return
     * @throws BusinessException
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    //不传入参数
    @RequestMapping("/getall")
    @ResponseBody
    public CommonResult getAllProduct() throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        List<ProductModel> productModelList = productService.getAll();
        return CommonResult.create(productModelList);
    }


    /**
     * 获取某个用户的产品信息
     *
     * @param user_id
     * @return
     * @throws BusinessException
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    //传入的参数是userid
    @RequestMapping("/getuserproduct")
    @ResponseBody
    public CommonResult getUserProduct(@RequestParam(name = "id") Integer user_id) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {

        List<ProductModel> productModelList = productService.getUserProduct(user_id);
        return CommonResult.create(productModelList);
    }


    /**
     * 获取某个商品的详细信息
     *
     * @param productid
     * @return
     * @throws BusinessException
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    @RequestMapping("/getproductinfo")
    @ResponseBody
    public CommonResult getProductInfo(@RequestParam(name = "id") Integer productid) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        List<ProductInfoDO> productInfoDOList = productService.getProductInfo(productid);
        return CommonResult.create(productInfoDOList);
    }


    /**
     * 提交产品Bom表
     *
     * @return
     * @throws BusinessException
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    @RequestMapping(value = "/submit", method = {RequestMethod.POST}, consumes = {"application/x-www-form-urlencoded"})
    @ResponseBody
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
    public CommonResult submitProduct(@RequestParam(name = "pro_name") String pro_name,
                                      @RequestParam(name = "pro_serial") String pro_serial,
                                      @RequestParam(name = "pro_factory") String pro_factory,
                                      @RequestParam(name = "pro_region") String pro_region,
                                      @RequestParam(name = "pro_origin") String pro_origin,
                                      @RequestParam(name = "pro_aim") String pro_aim,
                                      @RequestParam(name = "pro_power", required = false, defaultValue = "0") Integer pro_power,
                                      @RequestParam(name = "pro_distance", required = false, defaultValue = "0") Integer pro_distance,
                                      @RequestParam(name = "pro_life", required = false, defaultValue = "0") Integer pro_life,
                                      @RequestParam(name = "pro_weight", required = false, defaultValue = "0") Integer pro_weight,
                                      @RequestParam(name = "pro_parameter") String pro_parameter,
                                      @RequestParam(name = "pro_comments") String pro_comments,
                                      @RequestParam(name = "pro_userid") Integer pro_userid,
                                      @RequestParam(name = "pro_file") String pro_file) throws BusinessException, IOException, NoSuchAlgorithmException {

        //先存入产品信息表
        ProductModel productModel = new ProductModel();
        productModel.setName(pro_name);
        productModel.setSerial(pro_serial);
        productModel.setFactory(pro_factory);
        productModel.setRegion(pro_region);
        productModel.setOrigin(pro_origin);
        productModel.setAim(pro_aim);
        productModel.setPower(pro_power);
        productModel.setDistance(pro_distance);
        productModel.setLife(pro_life);
        productModel.setWeight(pro_weight);
        productModel.setParameter(pro_parameter);
        productModel.setComments(pro_comments);
        productModel.setUserId(pro_userid);


        List<String> orders=new ArrayList<>();
        InputStream in = null;
        try {
            Integer product_id=0;
            ExcelListener excelListener=null;
            try{
                product_id = productService.submitProduct(productModel);
                File file = new File(FileUtils.path + FileUtils.sep + pro_file);
                in = new FileInputStream(file);
            }catch (Exception e){
                log.error("文件上传失败！");
            }
            try{
                excelListener = new ExcelListener(productService, product_id, pro_userid, productInfoDOMapper, productDOMapper, bp, redisTemplate);
            }catch (Exception e){
                log.error("listener创建失败！");
            }

            try{
                EasyExcel.read(in, PartExcel.class, excelListener).sheet().doRead();
            }catch (Exception e){
                log.error("文件读取失败！");
            }

            orders=excelListener.orders;

        } catch (Exception e) {
            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "读取bom表出现错误！");
        }finally {
            in.close();
        }

        //判断序号是否正确
        //先对序号排序
        List<String> sortedList = sort(orders, 0, orders.size() - 1);
        //用HashSet去重
        HashSet<String> set=new HashSet<>();
        for(String i:sortedList){
            System.out.println(i);
            if(i.split("\\.").length==1){
                set.add(i);
            }else{
                //获取父序号 seaorder
                String[] os = i.split("\\.");
                //截取最后一个点前面的order
                String searorder="";
                for(int j=0;j<os.length-1;j++){
                    searorder+=os[j]+".";
                }
                searorder=searorder.substring(0,searorder.length()-1);
                if(!set.contains(searorder)){
                    throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, i+"序号有问题，找不到父序号！因为excel会自动把序号解析为double型数字,所以请删掉原序号手动输入"+i);
                }else{
                    set.add(i);
                }
            }
        }
        orders=null;
        return CommonResult.create(null);
    }

    public List<String> sort(List<String> list,int left,int right) {
        int povit=list.get((left+right)/2).split("\\.").length,l=left,r=right;
        while(l<r){
            while(list.get(l).split("\\.").length<povit) l++;
            while(list.get(r).split("\\.").length>povit) r--;
            if(l>=r) break;
            swap(list,r,l);
            if (list.get(r).split("\\.").length == povit) l++;
            if (list.get(l).split("\\.").length == povit) r--;
        }
        if (l == r) {
            l++;
            r--;
        }
        if (l < right) sort(list, l, right);
        if (left < r) sort(list, left, r);
        return list;
    }

    public void swap(List<String> list, int i, int j) {
        String temp = list.get(i);
        String t=list.get(j); //ArrayList不是一个安全的集合，所以此处先取出来
        list.set(i,t);  //防止出现fail-fast错误
        list.set(j,temp);
    }



    /**
     * 上传文件到内存中
     *
     * @param file
     * @return
     * @throws BusinessException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     */
    @RequestMapping(value = "/submitfile", method = {RequestMethod.POST}, consumes = {"application/x-www-form-urlencoded", "multipart/form-data"})
    @ResponseBody
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
    public CommonResult submitProduct(@RequestParam(name = "uploadfile") MultipartFile file) throws BusinessException, IOException, NoSuchAlgorithmException {
        if (file == null) {
            log.error("submitProduct：上传文件失败！");
            throw new BusinessException(new BusinessException(EmBusinessError.UNKNOWN_ERROR, "上传文件失败！"));
        }

        //cache.put(file.getOriginalFilename(),file);
        //cacheService.setCommonCache(file.getOriginalFilename(),file);
        InputStream in = file.getInputStream();
        FileUtils.savePic(in, file.getOriginalFilename());
        in.close();
        return CommonResult.create(null);
    }


    /**
     * 删除某个产品
     *
     * @param product_id
     * @return
     * @throws BusinessException
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    @RequestMapping("/delete")
    @ResponseBody
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
    public CommonResult deleteProduct(@RequestParam(name = "id") Integer product_id) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        productService.deleteById(product_id);
        //删除掉这个产品id下所有的计算相关的数据
        //1 先获取这个产品id下的计算对象
        List<ProductUseDO> productUseDOS = productUseDOMapper.selectByProductId(product_id);
        //2 遍历删除
        for (ProductUseDO i : productUseDOS) {
            productCalService.deleteById(i.getId());
        }

        return CommonResult.create(null);
    }

    /**
     * 查询图相关的展示
     *
     * @param productid
     * @return
     * @throws BusinessException
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    @RequestMapping("/graph")
    @ResponseBody
    public CommonResult queryGraph(@RequestParam(name = "id") Integer productid) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        return productService.queryProductGraphInfo(productid);
    }


    /**
     * 提交产品Bom表
     *
     * @return
     * @throws BusinessException
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    @RequestMapping(value = "/submitedit", method = {RequestMethod.POST}, consumes = {"application/x-www-form-urlencoded"})
    @ResponseBody
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
    public CommonResult submitEditProduct(@RequestParam(name = "pro_name") String pro_name,
                                          @RequestParam(name = "pro_serial") String pro_serial,
                                          @RequestParam(name = "pro_factory") String pro_factory,
                                          @RequestParam(name = "pro_region") String pro_region,
                                          @RequestParam(name = "pro_origin") String pro_origin,
                                          @RequestParam(name = "pro_aim") String pro_aim,
                                          @RequestParam(name = "pro_power", required = false, defaultValue = "0") Integer pro_power,
                                          @RequestParam(name = "pro_distance", required = false, defaultValue = "0") Integer pro_distance,
                                          @RequestParam(name = "pro_life", required = false, defaultValue = "0") Integer pro_life,
                                          @RequestParam(name = "pro_weight", required = false, defaultValue = "0") Integer pro_weight,
                                          @RequestParam(name = "pro_parameter") String pro_parameter,
                                          @RequestParam(name = "pro_comments") String pro_comments,
                                          @RequestParam(name = "pro_userid") Integer pro_userid,
                                          @RequestParam(name = "datas") JSONArray jsonArray) throws BusinessException, IOException, NoSuchAlgorithmException {

        //先存入产品信息表
        ProductModel productModel = new ProductModel();
        productModel.setName(pro_name);
        productModel.setSerial(pro_serial);
        productModel.setFactory(pro_factory);
        productModel.setRegion(pro_region);
        productModel.setOrigin(pro_origin);
        productModel.setAim(pro_aim);
        productModel.setPower(pro_power);
        productModel.setDistance(pro_distance);
        productModel.setLife(pro_life);
        productModel.setWeight(pro_weight);
        productModel.setParameter(pro_parameter);
        productModel.setComments(pro_comments);
        productModel.setUserId(pro_userid);

        Integer product_id = 0;
        List<ProductInfoDO> productInfoDOList = new ArrayList<>();
        try {
            product_id = productService.submitProduct(productModel);
        } catch (Exception e) {
            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "提交产品时发生异常！");
        }
        try {
            productInfoDOList = converformJSON(jsonArray, product_id, pro_userid);
        } catch (Exception e) {
            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "转换表格时发生异常！");
        }
        //ExcelListener excelListener = new ExcelListener(productService, product_id, pro_userid, productInfoDOMapper, productDOMapper);
        ExcelListener excelListener = new ExcelListener(productService, product_id, pro_userid, productInfoDOMapper, productDOMapper,bp,redisTemplate);
        for (int i = 0; i < productInfoDOList.size(); i++) {
            //智能补全数据
            ProductInfoDO t=excelListener.BPMakeDate(productInfoDOList.get(i));
            int i1 = productInfoDOMapper.insertSelective(t);
            if(i1==0){
                throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "插入数据时发生异常！");
            }
        }
        return CommonResult.create(null);
    }


    private List<ProductInfoDO> converformJSON(JSONArray jsonArray, Integer productid, Integer userid) {
        List<ProductInfoDO> result = new ArrayList<>();
        for (int i = 0; i < jsonArray.size(); i += 19) {
            ProductInfoDO temp = new ProductInfoDO();
            Object o = jsonArray.get(i);
            Object o1 = jsonArray.get(i + 1);
            Object o2 = jsonArray.get(i + 2);
            Object o3 = jsonArray.get(i + 3);
            Object o4 = jsonArray.get(i + 4);
            Object o5 = jsonArray.get(i + 5);
            Object o6 = jsonArray.get(i + 6);
            Object o7 = jsonArray.get(i + 7);
            Object o8 = jsonArray.get(i + 8);
            Object o9 = jsonArray.get(i + 9);
            Object o10 = jsonArray.get(i + 10);
            Object o11 = jsonArray.get(i + 11);
            Object o12 = jsonArray.get(i + 12);
            Object o13 = jsonArray.get(i + 13);
            Object o14 = jsonArray.get(i + 14);
            Object o15 = jsonArray.get(i + 15);
            Object o16 = jsonArray.get(i + 16);
            Object o18 = jsonArray.get(i + 18);
            temp.setId(null);
            String orderInfo = o1.toString().split(":")[1].substring(1, o1.toString().split(":")[1].length() - 1);
            temp.setOrderInfo(orderInfo);
            String codenameInfo = o2.toString().split(":")[1].substring(1, o2.toString().split(":")[1].length() - 1);
            temp.setCodenameInfo(codenameInfo);
            String nameInfo = o3.toString().split(":")[1].substring(1, o3.toString().split(":")[1].length() - 1);
            temp.setNameInfo(nameInfo);
            String serialInfo = o4.toString().split(":")[1].substring(1, o4.toString().split(":")[1].length() - 1);
            temp.setSerialInfo(serialInfo);
            String functionInfo = o5.toString().split(":")[1].substring(1, o5.toString().split(":")[1].length() - 1);
            temp.setFunctionInfo(functionInfo);
            String parameterInfo = o6.toString().split(":")[1].substring(1, o6.toString().split(":")[1].length() - 1);
            temp.setParameterInfo(parameterInfo);
            String numeveryInfo = o7.toString().split(":")[1];
            temp.setNumeveryInfo(Integer.parseInt(remove(numeveryInfo)));
            String materialInfo = o8.toString().split(":")[1].substring(1, o8.toString().split(":")[1].length() - 1);
            temp.setMaterialInfo(remove(materialInfo));
            String weighteveryInfo = o9.toString().split(":")[1];
            temp.setWeighteveryInfo(Integer.parseInt(remove(weighteveryInfo)));
            String weighttotalInfo = o10.toString().split(":")[1];
            temp.setWeighttotalInfo(new BigDecimal(remove(weighttotalInfo)));
            String commentsInfo = o11.toString().split(":")[1].substring(1, o11.toString().split(":")[1].length() - 1);
            temp.setCommentsInfo(remove(commentsInfo));
            String originInfo = o12.toString().split(":")[1].substring(1, o12.toString().split(":")[1].length() - 1);
            temp.setOriginInfo(remove(originInfo));
            String distanceInfo = o13.toString().split(":")[1];
            temp.setDistanceInfo(Integer.parseInt(remove(distanceInfo)));
            String transportstyleInfo = o14.toString().split(":")[1].substring(1, o14.toString().split(":")[1].length() - 1);
            temp.setTransportstyleInfo(remove(transportstyleInfo));
            String manufacturestyleInfo = o15.toString().split(":")[1].substring(1, o15.toString().split(":")[1].length() - 1);
            temp.setManufacturestyleInfo(remove(manufacturestyleInfo));
            String recycleInfo = o16.toString().split(":")[1];
            temp.setRecycleInfo(Integer.parseInt(remove(recycleInfo)));
            Integer productId = productid;
            temp.setProductId(productId);
            temp.setUserId(userid);
            result.add(temp);
        }

        return result;
    }

    public String remove(String str){
        StringBuilder sb=new StringBuilder();
        for(int i=0;i<str.length();i++){
            if(str.charAt(i)!='"'&&str.charAt(i)!=':'){
                sb.append(str.charAt(i));
            }
        }
        return sb.toString();
    }


}
